package com.fbs.job.admin.service.impl;

import com.fbs.job.admin.core.entity.FbsJobActuator;
import com.fbs.job.admin.core.entity.FbsJobInfo;
import com.fbs.job.admin.core.enums.*;
import com.fbs.job.admin.core.thread.JobScheduleHelper;
import com.fbs.job.admin.core.util.CronExpression;
import com.fbs.job.admin.mapper.FbsJobActuatorMapper;
import com.fbs.job.admin.mapper.FbsJobInfoMapper;
import com.fbs.job.admin.mapper.FbsJobLogMapper;
import com.fbs.job.admin.service.JobInfoService;
import com.fbs.job.core.enums.ExecutorBlockStrategyEnum;
import com.fbs.job.core.glue.GlueTypeEnum;
import com.fbs.job.core.model.ResultT;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 描述：
* @author wwd
* @date 2024-01-31 14:08:16
*/

@Service
public class JobInfoServiceImpl implements JobInfoService {

    @Resource
    FbsJobInfoMapper fbsJobInfoMapper;
    @Resource
    FbsJobActuatorMapper fbsJobActuatorMapper;
    @Resource
    FbsJobLogMapper fbsJobLogMapper;

    @Override
    public Map<String, Object> pageList(int start, int length, int jobActuator, int triggerStatus, String jobDesc, String executorHandler, String author) {
        // page list
        List<FbsJobInfo> list = fbsJobInfoMapper.pageList(start-1, length, jobActuator, triggerStatus, jobDesc, executorHandler, author);
        int list_count = fbsJobInfoMapper.pageListCount(start-1, length, jobActuator, triggerStatus, jobDesc, executorHandler, author);

        // package result
        Map<String, Object> maps = new HashMap<String, Object>();
        maps.put("recordsTotal", list_count);		// 总记录数
        maps.put("recordsFiltered", list_count);	// 过滤后的总记录数
        maps.put("data", list);  					// 分页列表
        maps.put("code",0);
        return maps;
    }

    @Override
    public FbsJobInfo getById(int id) {
        return fbsJobInfoMapper.getById(id);
    }

    @Override
    public ResultT<String> add(FbsJobInfo jobInfo) {
        if (jobInfo.getJobActuator() == null){
            return ResultT.error("请选择执行器");
        }
        // valid base
        FbsJobActuator actuator = fbsJobActuatorMapper.getById(jobInfo.getJobActuator());
        if (null == actuator){
            return   ResultT.error("请选择执行器");
        }
        if (StringUtils.isBlank(jobInfo.getJobDesc())){
            return  ResultT.error("任务描述不能为空");
        }
        if (StringUtils.isBlank(jobInfo.getAuthor())){
            return   ResultT.error("请填写责任人");
        }

        ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
        if (scheduleTypeEnum == null) {
           return   ResultT.error("请选择调度类型");
        }
        if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {
            if (jobInfo.getScheduleConf()==null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {
                return ResultT.error("CORN 非法");
            }
        }else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE){
            if (jobInfo.getScheduleConf() == null) {
                return ResultT.error("固定速率不能为空");
            }
            try {
                int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());
                if (fixSecond < 1) {
                    return ResultT.error("固定速率非法");
                }
            } catch (Exception e) {
                return ResultT.error("固定速率非法填写错误");
            }
        }

        // valid job
        if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
            return ResultT.error("运行模式填写错误");
        }

        if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && (jobInfo.getExecutorHandler()==null || jobInfo.getExecutorHandler().trim().length()==0) ) {
            return ResultT.error("执行器任务handler不能为空");
        }
//        // 》fix "\r" in shell
//        if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource()!=null) {
//            jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", ""));
//        }


        // valid advanced
        if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
            return ResultT.error("路由策略非法");
        }
        if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {
            return ResultT.error("调度过期策略非法");
        }

        if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
            return ResultT.error("阻塞处理策略非法");
        }



        // 》ChildJobId valid
        if (jobInfo.getChildJobid()!=null && jobInfo.getChildJobid().trim().length()>0) {
            String[] childJobIds = jobInfo.getChildJobid().split(",");
            for (String childJobIdItem: childJobIds) {
                if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && NumberUtils.isDigits(childJobIdItem)) {
                    FbsJobInfo childJobInfo = fbsJobInfoMapper.getById(Integer.parseInt(childJobIdItem));
                    if (childJobInfo==null) {
                        return new ResultT<>(ResultT.FAIL_CODE,
                                MessageFormat.format(("子任务ID"+"({0})"+"未找到"), childJobIdItem));
                    }
                } else {
                    return new ResultT<>(ResultT.FAIL_CODE,
                            MessageFormat.format(("子任务ID"+"({0})"+"非法"), childJobIdItem));
                }
            }

            // join , avoid "xxx,,"
            String temp = "";
            for (String item:childJobIds) {
                temp += item + ",";
            }
            temp = temp.substring(0, temp.length()-1);

            jobInfo.setChildJobid(temp);
        }
// add in db
        jobInfo.setAddTime(new Date());
        jobInfo.setUpdateTime(new Date());
        jobInfo.setGlueUpdatetime(new Date());
        fbsJobInfoMapper.save(jobInfo);
        if (jobInfo.getId() < 1) {
            return new ResultT<>(ResultT.FAIL_CODE, "任务保存失败" );
        }


        return  ResultT.success(String.valueOf(jobInfo.getId()));
    }

    @Override
    public ResultT<String> stop(int id) {
        FbsJobInfo fbsJobInfo = fbsJobInfoMapper.getById(id);

        fbsJobInfo.setTriggerStatus(0);
        fbsJobInfo.setTriggerLastTime(0);
        fbsJobInfo.setTriggerNextTime(0);

        fbsJobInfo.setUpdateTime(new Date());
        fbsJobInfoMapper.update(fbsJobInfo);
        return ResultT.success();
    }

    @Override
    public ResultT<String> start(int id) {
        FbsJobInfo xxlJobInfo = fbsJobInfoMapper.getById(id);

        // valid
        ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(xxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE);
        if (ScheduleTypeEnum.NONE == scheduleTypeEnum) {
            return new ResultT<String>(ResultT.FAIL_CODE, "当前调度类型禁止启动" );
        }

        // next trigger time (5s后生效，避开预读周期)
        long nextTriggerTime = 0;
        try {
            Date nextValidTime = JobScheduleHelper.generateNextValidTime(xxlJobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
            if (nextValidTime == null) {
                return new ResultT<String>(ResultT.FAIL_CODE, ("调度类型非法"));
            }
            nextTriggerTime = nextValidTime.getTime();
        } catch (Exception e) {
            return new ResultT<String>(ResultT.FAIL_CODE, "调度类型非法" );
        }

        xxlJobInfo.setTriggerStatus(1);
        xxlJobInfo.setTriggerLastTime(0);
        xxlJobInfo.setTriggerNextTime(nextTriggerTime);

        xxlJobInfo.setUpdateTime(new Date());
        fbsJobInfoMapper.update(xxlJobInfo);
        return ResultT.success();
    }

    @Override
    public ResultT<String> update(FbsJobInfo jobInfo) {

        // valid base
        if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
            return new ResultT<String>(ResultT.FAIL_CODE, "请输入任务描述" );
        }
        if (jobInfo.getAuthor()==null || jobInfo.getAuthor().trim().length()==0) {
            return new ResultT<String>(ResultT.FAIL_CODE, "请输入负责人") ;
        }

        // valid trigger
        ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
        if (scheduleTypeEnum == null) {
            return new ResultT<String>(ResultT.FAIL_CODE, "调度类型非法" );
        }
        if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {
            if (jobInfo.getScheduleConf()==null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {
                return new ResultT<String>(ResultT.FAIL_CODE, "Cron非法" );
            }
        } else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE ) {
            if (jobInfo.getScheduleConf() == null) {
                return new ResultT<String>(ResultT.FAIL_CODE, "调度类型非法" );
            }
            try {
                int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());
                if (fixSecond < 1) {
                    return new ResultT<String>(ResultT.FAIL_CODE, "调度类型非法");
                }
            } catch (Exception e) {
                return new ResultT<String>(ResultT.FAIL_CODE,"调度类型非法" );
            }
        }

        // valid advanced
        if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
            return new ResultT<String>(ResultT.FAIL_CODE, "路由策略非法");
        }
        if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {
            return new ResultT<String>(ResultT.FAIL_CODE, "调度过期策略非法" );
        }
        if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
            return new ResultT<String>(ResultT.FAIL_CODE, "阻塞处理策略非法");
        }

        // 》ChildJobId valid
        if (jobInfo.getChildJobid()!=null && jobInfo.getChildJobid().trim().length()>0) {
            String[] childJobIds = jobInfo.getChildJobid().split(",");
            for (String childJobIdItem: childJobIds) {
                if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && NumberUtils.isDigits(childJobIdItem)) {
                    FbsJobInfo childJobInfo = fbsJobInfoMapper.getById(Integer.parseInt(childJobIdItem));
                    if (childJobInfo==null) {
                        return new ResultT<>(ResultT.FAIL_CODE,
                                MessageFormat.format(("子任务ID"+"({0})"+"未找到"), childJobIdItem));
                    }
                } else {
                    return new ResultT<>(ResultT.FAIL_CODE,
                            MessageFormat.format(("子任务ID"+"({0})"+"非法"), childJobIdItem));
                }
            }

            // join , avoid "xxx,,"
            String temp = "";
            for (String item:childJobIds) {
                temp += item + ",";
            }
            temp = temp.substring(0, temp.length()-1);

            jobInfo.setChildJobid(temp);
        }

        // group valid
        FbsJobActuator jobActuator = fbsJobActuatorMapper.getById(jobInfo.getJobActuator());
        if (jobActuator == null) {
            return new ResultT<>(ResultT.FAIL_CODE, "执行器非法" );
        }

        // stage job info
        FbsJobInfo exists_jobInfo = fbsJobInfoMapper.getById(jobInfo.getId());
        if (exists_jobInfo == null) {
            return new ResultT<String>(ResultT.FAIL_CODE,"任务ID系统未找到" );
        }

        // next trigger time (5s后生效，避开预读周期)
        long nextTriggerTime = exists_jobInfo.getTriggerNextTime();
        boolean scheduleDataNotChanged = jobInfo.getScheduleType().equals(exists_jobInfo.getScheduleType()) && jobInfo.getScheduleConf().equals(exists_jobInfo.getScheduleConf());
        if (exists_jobInfo.getTriggerStatus() == 1 && !scheduleDataNotChanged) {
            try {
                Date nextValidTime = JobScheduleHelper.generateNextValidTime(jobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
                if (nextValidTime == null) {
                    return new ResultT<String>(ResultT.FAIL_CODE,"调度类型非法" );
                }
                nextTriggerTime = nextValidTime.getTime();
            } catch (Exception e) {
                return new ResultT<String>(ResultT.FAIL_CODE, "调度类型非法" );
            }
        }

        exists_jobInfo.setJobActuator(jobInfo.getJobActuator());
        exists_jobInfo.setJobDesc(jobInfo.getJobDesc());
        exists_jobInfo.setAuthor(jobInfo.getAuthor());
        exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail());
        exists_jobInfo.setScheduleType(jobInfo.getScheduleType());
        exists_jobInfo.setScheduleConf(jobInfo.getScheduleConf());
        exists_jobInfo.setMisfireStrategy(jobInfo.getMisfireStrategy());
        exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());
        exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler());
        exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());
        exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
        exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());
        exists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());
        exists_jobInfo.setChildJobid(jobInfo.getChildJobid());
        exists_jobInfo.setTriggerNextTime(nextTriggerTime);

        exists_jobInfo.setUpdateTime(new Date());
        fbsJobInfoMapper.update(exists_jobInfo);


        return ResultT.success();
    }

    @Override
    public ResultT<String> delete(int id) {
        FbsJobInfo fbsJobInfo = fbsJobInfoMapper.getById(id);
        if (fbsJobInfo == null) {
            return ResultT.success();
        }
        if ( fbsJobInfo.getTriggerStatus()==1){
            return ResultT.error("该任务正在运行中，不能删除...");
        }
        fbsJobInfoMapper.delete(id);
        fbsJobLogMapper.deleteByJobId(id);
        return ResultT.success();
    }
}
